/*
 * @(#)GenerateBean.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.sql.Types;
import java.util.Calendar;
import java.util.Hashtable;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
  GenerateBean.java

  This class is for generation of bean object.

    @author           Rollo Chan
    @company          DCIVision Limited
    @creation date    26/06/2003
    @version          $Revision: 1.19.32.1 $
*/

public class GenerateBean {

  public static final String REVISION = "$Revision: 1.19.32.1 $";

  static String author = null;
  static String srcPath = null;
  static String driverStr = null;
  static String dbConnStr = null;
  static String dbUsername = null;
  static String dbPassword = null;

  static String packageName = "com.dcivision.";

  static final String JAVA_INTEGER = "Integer";
  static final String JAVA_DECIMAL = "Float";
  static final String JAVA_STRING = "String";
  static final String JAVA_DATE = "Timestamp";

  static Connection conn = null;
  static String sqlStat = null;
  static Statement stat = null;
  static ResultSet rs = null;
  static ResultSetMetaData rsmd = null;

  static PrintStream out = null;
  static String srcFileName = null;
  static String tableName = null;
  static String className = "";

  static Hashtable exceptionFields = new Hashtable();
  static boolean hasRecordStatus = false;
  private static final Log log = LogFactory.getLog(GenerateBean.class);
  public static void main(String[] argv) throws Exception {
    // Load properties in the "src" directory.
    java.util.Properties props = new java.util.Properties();
    String path = new GenerateBean().getClass().getProtectionDomain().getCodeSource().getLocation().toString().substring(6);
    if (!path.endsWith("/")) {
      path += "/";
    }
    path += "generate.properties";
    java.io.FileInputStream fis = new java.io.FileInputStream(new java.io.File(path));
    props.load(fis);

    author = props.getProperty("author");
    srcPath = props.getProperty("srcPath");
    driverStr = props.getProperty("driverStr");
    dbConnStr = props.getProperty("dbConnStr");
    dbUsername = props.getProperty("dbUsername");
    dbPassword = props.getProperty("dbPassword");

    // Initialize those common fields which NOT need to generate.
    exceptionFields.put("ID", "Y");
    exceptionFields.put("CREATOR_ID", "Y");
    exceptionFields.put("CREATE_DATE", "Y");
    exceptionFields.put("UPDATER_ID", "Y");
    exceptionFields.put("UPDATE_DATE", "Y");
    exceptionFields.put("RECORD_STATUS", "Y");
    exceptionFields.put("UPDATE_COUNT", "Y");
    hasRecordStatus = true;

    // Check the usage.
    if (argv.length != 2 && argv.length != 3) {
      System.out.println("Usage: java GenerateBean <TABLE_NAME> <PACKAGE_NAME>");
      return;
    }

    // Initialize file and class settings.
    argv[0] = argv[0].toLowerCase();
    String[] tmpAry = splitString(argv[0], "_");
    for (int i = 0; i < tmpAry.length; i++) {
      className += Character.toUpperCase(tmpAry[i].charAt(0)) + tmpAry[i].substring(1);
    }
    tableName = argv[0];
    packageName += argv[1];
    srcFileName = srcPath + "/src/" + replaceString(packageName, ".", "/") + "/bean/" + className + ".java";

    // Open source file.
    openSrcFile();

    // Print the program header.
    printHeader();

    // Initialize database connection.
    openDBConn();

    // Print private member.
    printPrivateMember();

    // Print constructors.
    printConstructor();

    // Print get and set methods.
    printGetSetMethod();

    // Initialize database connection.
    closeDBConn();

    // Print the program footer.
    printFooter();

    // Close source file.
    closeSrcFile();
  }

  public static void printConstructor() throws Exception {
    out.println();
    out.println("  public " + className + "() {");
    out.println("    super();");
    out.println("  }");
  }

  public static void printGetSetMethod() throws Exception {
    for (int i = 1; i <= rsmd.getColumnCount(); i++) {
      if (exceptionFields.get(rsmd.getColumnName(i).toUpperCase()) == null) {
        // get method.
        out.println();
        out.println("  public " + getJavaType(rsmd, i) + " get" + getVariableName(rsmd.getColumnName(i), true) + "() { ");
        out.println("    return(this." + getVariableName(rsmd.getColumnName(i)) + ");");
        out.println("  }");

        // set method.
        out.println();
        out.println("  public void set" + getVariableName(rsmd.getColumnName(i), true) + "(" + getJavaType(rsmd, i) + " " + getVariableName(rsmd.getColumnName(i)) + ") { ");
        out.println("    this." + getVariableName(rsmd.getColumnName(i)) + " = " + getVariableName(rsmd.getColumnName(i)) + ";");
        out.println("  }");
      }
    }
  }

  public static void printPrivateMember() throws Exception {
    for (int i = 1; i <= rsmd.getColumnCount(); i++) {
      if (exceptionFields.get(rsmd.getColumnName(i).toUpperCase()) == null) {
        if (JAVA_INTEGER.equals(getJavaType(rsmd, i))) {       // int
          out.println("  private " + getJavaType(rsmd, i) + " " + getVariableName(rsmd.getColumnName(i)) + " = null;");
        } else if (JAVA_DECIMAL.equals(getJavaType(rsmd, i))) {  // double
          out.println("  private " + getJavaType(rsmd, i) + " " + getVariableName(rsmd.getColumnName(i)) + " = null;");
        } else if (JAVA_STRING.equals(getJavaType(rsmd, i))) {  // String
          out.println("  private " + getJavaType(rsmd, i) + " " + getVariableName(rsmd.getColumnName(i)) + " = null;");
        } else if (JAVA_DATE.equals(getJavaType(rsmd, i))) {  // Date
          out.println("  private " + getJavaType(rsmd, i) + " " + getVariableName(rsmd.getColumnName(i)) + " = null;");
        }
      }
    }
  }

  public static void openDBConn() throws Exception {
    Class.forName(driverStr);
    conn = DriverManager.getConnection(dbConnStr, dbUsername, dbPassword);

    sqlStat = "SELECT * FROM " + tableName.toUpperCase();
    stat = conn.createStatement();
    stat.setMaxRows(1);
    rs = stat.executeQuery(sqlStat);
    rsmd = rs.getMetaData();
  }

  public static void closeDBConn() throws Exception {
    try { rs.close(); } catch (Exception ignore) {} finally { rs = null; }
    try { stat.close(); } catch (Exception ignore) {} finally { stat = null; }
    try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
  }

  public static void printHeader() throws Exception {
    // Print the program header.
    Calendar now = Calendar.getInstance();
    String[] month = { "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12" };
    out.println("/*");
    out.println(" * @(#)" + className + ".java");
    out.println(" *");
    out.println(" * Copyright (c) 2003 DCIVision Ltd");
    out.println(" * All rights reserved.");
    out.println(" *");
    out.println(" * This software is the confidential and proprietary information of DCIVision");
    out.println(" * Ltd (\"Confidential Information\").  You shall not disclose such Confidential");
    out.println(" * Information and shall use it only in accordance with the terms of the license");
    out.println(" * agreement you entered into with DCIVision Ltd.");
    out.println(" */");
    out.println("package " + packageName + ".bean;");
    out.println();
    out.println("import java.sql.*;");
    out.println("import java.util.*;");
    out.println("import com.dcivision.framework.*;");
    out.println("import com.dcivision.framework.bean.*;");
    out.println("import com.dcivision.framework.dao.*;");
    out.println();
    out.println("/**");
    out.println("  " + className + ".java");
    out.println();
    out.println("  This class is the serializable bean reflecting business logic uses.");
    out.println();
    out.println("    @author           " + author);
    out.println("    @company          DCIVision Limited");
    out.println("    @creation date    " + (now.get(Calendar.DAY_OF_MONTH) < 10 ? ("0" + now.get(Calendar.DAY_OF_MONTH)) : ("" + now.get(Calendar.DAY_OF_MONTH))) + "/" + month[now.get(Calendar.MONTH)] + "/" + now.get(Calendar.YEAR));
    out.println("    @version          $Revision: 1.19.32.1 $");
    out.println("*/");
    out.println();
    out.println("public class " + className + " extends AbstractBaseObject {");
    out.println();
    out.println("  public static final String REVISION = \"$Revision: 1.19.32.1 $\";");
    out.println();
  }

  public static void printFooter() throws Exception {
    out.println("}");
  }

  public static void openSrcFile() throws Exception {
    try {
      out = new PrintStream(new FileOutputStream(srcFileName, false), true);
    } catch (Exception e) {
      out = System.out;
    }
  }

  public static void closeSrcFile() throws Exception {
    try { out.close(); } catch (Exception ignore) {} finally { out = null; }
  }

  public static String getVariableName(String dbColName) {
    return(getVariableName(dbColName, false));
  }

  public static String getVariableName(String dbColName, boolean capInitFlag) {
    String result = "";
    String[] tmpAry = splitString(dbColName.toLowerCase(), "_");
    for (int i = 0; i < tmpAry.length; i++) {
      String tmp = Character.toUpperCase(tmpAry[i].charAt(0)) + tmpAry[i].substring(1);
      if ("id".equals(tmp.toLowerCase())) {
        result += "ID";
      } else {
        result += tmp;
      }
    }
    if (capInitFlag) {
      return(result);
    } else {
      if (result.toLowerCase().equals("id") && !capInitFlag) {
        return("id");
      } else {
        return(Character.toLowerCase(result.charAt(0)) + result.substring(1));
      }
    }
  }

  public static String getJavaType(ResultSetMetaData inRSMD, int idx) throws Exception {
    System.out.println(inRSMD.getColumnName(idx) + ":" + inRSMD.getColumnTypeName(idx) + ":" + inRSMD.getColumnType(idx) + ":" + inRSMD.getPrecision(idx));
    if ((inRSMD.getColumnType(idx)==Types.BIGINT) || (inRSMD.getColumnType(idx)==Types.INTEGER)) {      // int
      return(JAVA_INTEGER);
    } else if ((inRSMD.getColumnType(idx)==Types.FLOAT) || (inRSMD.getColumnType(idx)==Types.DECIMAL) || (inRSMD.getColumnType(idx)==Types.DOUBLE)) {   // double
      return(JAVA_DECIMAL);
    } else if ((inRSMD.getColumnType(idx)==Types.VARCHAR) || (inRSMD.getColumnType(idx)==Types.CHAR) || (inRSMD.getColumnType(idx)==Types.LONGVARCHAR)) {  // String
      return(JAVA_STRING);
    } else if ((inRSMD.getColumnType(idx)==Types.DATE) || (inRSMD.getColumnType(idx)==Types.TIMESTAMP)) {  // Date
      return(JAVA_DATE);
    } else {
      return("<UNKNOWN>");
    }
  }

  /**
   * splitString
   *
   * Returns string array which after spliting the input string.
   *
   * @param   src   String which going to be splitted.
   * @param   div   Delimitator for split.
   * @return    String array after split.
   */
  public static String[] splitString(String src, String div) {
    String[] result = null;
    java.util.Vector temp = new java.util.Vector();
    int idx1 = 0;
    int idx2 = 0;

    if (src == null || src.length() == 0 || div == null || div.length() == 0) {
    return(null);
    }

    try {
    while (idx2 >= 0 && idx1 < src.length()) {
      idx2 = src.indexOf(div, idx1);
      if (idx2 >= 0) {
      temp.addElement(src.substring(idx1, idx2));
      } else {
      temp.addElement(src.substring(idx1));
      }
      idx1 = idx2 + div.length();
    }

    result = new String[temp.size()];
    for (int i = 0; i < temp.size(); i++) {
      result[i] = (String)temp.elementAt(i);
    }

    return(result);
    } catch (Exception e) {
      log.error(e, e);
      return(null);
    }
  }

  /**
   * splitString
   *
   * Returns string array which after spliting the input string using space as delimitator.
   *
   * @param   src String which going to be splitted using space as delimitator.
   * @return    String array after split.
   */
  public static String[] splitString(String src) {
    return(splitString(src, " "));
  }

  /**
   * replaceString
   *
   * Returns string after replacing the original string to the target string, no matter
   * the ori string wrapped by space or charater.
   *
   * @param   src Source string which going to be replaced
   * @param   ori Original string in the source string
   * @param   tar Target string which replaces the original string
   * @return    String after replacement taken place.
   */
  public static String replaceString(String src, String ori, String tar) {
    String result = null;

    if (src!=null && ori!=null && tar!=null){
      try {
        StringBuffer source = new StringBuffer(src);
        int appearedIndex = 0;
        int oriLength = ori.length();
        int tarLength = tar.length();
        int byPassingIndex = 0;
        // If you got exception here, please check your JDK version. JDK 1.4 is needed for this method.
        while (source.indexOf(ori, byPassingIndex) != -1) {
          appearedIndex = source.indexOf(ori, byPassingIndex);
          if (ori.equals(source.substring(appearedIndex,
                                          appearedIndex + oriLength))) {
            source = source.replace(appearedIndex, appearedIndex + oriLength,
                                    tar);
            byPassingIndex = appearedIndex + tarLength;
          }
          else {
            byPassingIndex = appearedIndex;
          }
        }
        result = source.toString();
      }
      catch (Exception e) {
        log.error(e, e);
      }
    }
    return result;
  }

}
